﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace CoreSimple
{

    public class RedpackTest
    {
        public RedpackTest()
        {

        }
        public void Valid(Redpack pack)
        {
            DateTime d = DateTime.Now;
            ConcurrentBag<decimal> values = new ConcurrentBag<decimal>();

            List<Task> tasks = new List<Task>();
            for (int i = 0; i < pack.Number; i++)
            {
                var t = Task.Run(() =>
                {
                    decimal m = pack.Next();
                    values.Add(m);
                    Console.WriteLine("我抢到: ￥{0:N2} , T: {1}", m, Thread.CurrentThread.ManagedThreadId);
                });

                tasks.Add(t);
            }

            Task.WhenAll(tasks).ContinueWith((t, o) =>
            {
                decimal[] dms = values.ToArray();
                decimal amount = 0;
                foreach (decimal item in dms) amount += item;

                Console.WriteLine("Amount:{2}, Number: {3} Validate Result: {0}, UseTime: {1}/秒", amount == pack.Amount, (DateTime.Now - d).TotalSeconds, pack.Amount, pack.Number);
            }, null);
        }

        public Redpack Create()
        {
            double rn = new Random().NextDouble();
            double m = rn * 200;// 最大200块
            if (rn > 0)
            {
                m = Math.Ceiling(m * 100) / 100;
                double max = Math.Floor(m * 100);
                if (max > 500) max = 500;

                int n = new Random().Next(1, Convert.ToInt32(max));

                decimal dm = Convert.ToDecimal(m);
                return new Redpack(dm, n);
            }
            return null;
        }
    }

    public class Redpack
    {
        public readonly decimal Amount = 0;
        public readonly int Number = 0;

        private decimal takeAmount = 0;
        private int takeNumber = 0;

        public readonly long Id;

        private bool isEmpty = false;
        public bool IsEmpty { get => isEmpty; }
        public decimal TakeAmount { get => takeAmount; }
        public int TakeNumber { get => takeNumber; }


        public Redpack(decimal amount, int number)
        {
            Amount = amount;
            Number = number;

            Id = DotNetExtensions.Core.Snowflake.Default.NextId();
        }

        public bool CanNext()
        {
            return !(isEmpty = takeNumber >= Number || takeAmount > Amount);
        }

        public decimal Next()
        {
            lock (this)
            {
                if (CanNext() == false) throw new Exception("手慢了，红包已被抢完！");

                decimal ret = 0;

                int remainNumber = Number - takeNumber;
                decimal remainAmount = Amount - takeAmount;

                if (remainNumber == 1)
                {
                    ret = Amount - takeAmount;
                    takeNumber = Number;
                    takeAmount = Amount;
                    return ret;
                }
                decimal limitAmount = Convert.ToDecimal((remainNumber - 1) * 0.01);

                if (Amount - takeAmount == limitAmount)
                {
                    takeNumber += 1;
                    takeAmount += new decimal(0.01);
                    return new decimal(0.01);
                }

                double range = Convert.ToDouble(remainAmount / remainNumber * 2);
                int rn = new Random().Next(1, 100);
                double take = range * rn;
                double tmp = take;
                if (tmp < 1) tmp = 1;
                ret = Convert.ToDecimal(Math.Floor(tmp) / 100);

                takeNumber += 1;
                takeAmount += ret;

                return ret;
            }
        }
    }
}
